/**
 * @file ErrorHandlerFacade.h
 * @brief Provides a simplified facade interface for `errors::ErrorHandler`,
 * optimized for use in libraries where the caller defines final error handling.
 *
 * This class, residing in the 'utils' namespace, wraps an instance of `errors::ErrorHandler`.
 * It's designed to be instantiated by a library and then exposed (e.g., via a raw pointer)
 * to the library's caller. The caller can then register a custom error callback to integrate
 * with their own logging or error management system.
 *
 * The static factory method `createInstance` is the recommended way to create instances.
 * For library use, the callback is typically NOT set at creation time via `createInstance`;
 * instead, the library exposes a way for its caller to set the callback later using `setErrorCallback`.
 *
 * -------------------------------------------------------------------------------------------------------------------------
 * REVISION HISTORY
 * -------------------------------------------------------------------------------------------------------------------------
 * | Version   | Date       | Author        | Ticket Id | Description                                           |
 * |-----------|------------|---------------|-----------|-------------------------------------------------------|
 * | 1.0       | 2025-05-19 | AI Assistant  | N/A       | Initial definition.                                   |
 * | 1.1       | 2025-05-19 | AI Assistant  | N/A       | Confirmed 'utils' namespace, interaction with 'errors'.|
 * | 1.2       | 2025-05-19 | AI Assistant  | N/A       | Adjusted for dynamic library usage: callback set by caller, facade exposed directly. |
 * -------------------------------------------------------------------------------------------------------------------------
 * COPYRIGHT
 * -------------------------------------------------------------------------------------------------------------------------
 * \verbatim
 * Copyright (c) 2024-2025 by <company name>. All rights reserved.
 * \endverbatim
 */
#pragma once

#include "ErrorHandler.h" // Dependency on the core ErrorHandler
#include "GlobalErrorDefs.h"
#include <functional>
#include <string>
#include <optional>
#include <memory> // For std::unique_ptr and std::make_unique

namespace utils {

/**
 * @class ErrorHandlerFacade
 * @brief A facade for `errors::ErrorHandler` to simplify its integration and standardize error handling,
 * particularly for libraries.
 *
 * Manages an internal `errors::ErrorHandler` instance. A library would typically create an instance
 * of this facade (e.g., as a private member of a service class) and then provide a public
 * accessor method (e.g., `getErrorHandlingInterface()`) that returns a raw pointer to this facade.
 * The library's caller can then use this pointer to set a custom error callback and/or retrieve
 * queued errors.
 *
 * @see errors::ErrorHandler
 * @see common_defs::ErrorCode
 */
class ErrorHandlerFacade {
private:
    errors::ErrorHandler m_errorHandlerInstance; ///< Internal instance of the core error handler.

    // Private constructor to encourage use of the static factory method.
    ErrorHandlerFacade() = default;

public:
    ~ErrorHandlerFacade() = default;

    // Movable but not copyable, reflecting ownership of m_errorHandlerInstance.
    ErrorHandlerFacade(const ErrorHandlerFacade&) = delete;
    ErrorHandlerFacade& operator=(const ErrorHandlerFacade&) = delete;
    ErrorHandlerFacade(ErrorHandlerFacade&& other) noexcept = default;
    ErrorHandlerFacade& operator=(ErrorHandlerFacade&& other) noexcept = default;

    /**
     * @brief Static factory method to create an `ErrorHandlerFacade` instance.
     *
     * This is the recommended way to create `ErrorHandlerFacade` objects.
     *
     * @param initialCallback Optional: An initial error callback.
     * **For library developers**: It's generally recommended to pass `nullptr` here.
     * The library should expose this facade instance (or its `setErrorCallback` method)
     * so the library's CALLER can register their specific callback.
     * @param enqueueErrorsByDefault If true (default), errors reported via `setError` will be added
     * to the internal queue of `errors::ErrorHandler` even before a specific callback is set
     * by the caller, or if the caller's callback also wishes for them to be enqueued.
     * This allows errors to be potentially retrieved later via `getNextError()`.
     * @return A `std::unique_ptr<ErrorHandlerFacade>` to the newly created instance.
     *
     * @code
     * // Library's internal creation:
     * // auto facade = utils::ErrorHandlerFacade::createInstance(nullptr, true);
     * // Then, the library would expose 'facade.get()' to its caller.
     *
     * // Caller's usage:
     * // utils::ErrorHandlerFacade* libErrorHandler = myLibrary.getErrorHandlingInterface();
     * // if (libErrorHandler) {
     * //   libErrorHandler->setErrorCallback([](const errors::ErrorHandler::ErrorInfo& ei) {
     * //     std::cerr << "App insight: " << ei.message << std::endl;
     * //   }, true); // Caller decides if errors also queue for getNextError
     * // }
     * @endcode
     */
    [[nodiscard("Factory method creates an instance that should be captured.")]]
    static std::unique_ptr<ErrorHandlerFacade> createInstance(
        std::function<void(const errors::ErrorHandler::ErrorInfo&)> initialCallback = nullptr,
        bool enqueueErrorsByDefault = true) {
        auto facade = std::unique_ptr<ErrorHandlerFacade>(new ErrorHandlerFacade()); // Using private constructor
        // Configure the internal ErrorHandler. If initialCallback is nullptr,
        // ErrorHandler should still respect enqueueErrorsByDefault for its internal queueing.
        facade->m_errorHandlerInstance.setErrorCallback(std::move(initialCallback), enqueueErrorsByDefault);
        return facade;
    }

    /**
     * @brief Registers an error callback function with the internal `errors::ErrorHandler`.
     * This is the primary method for a library's CALLER to inject their custom error handling logic.
     * @see errors::ErrorHandler::setErrorCallback
     * @param callback The function to call when an error is set. Signature: `void(const errors::ErrorHandler::ErrorInfo&)`
     * Passing `nullptr` can be used to clear a previously set callback.
     * @param enqueueErrorsAfterCallback If true, errors will still be added to the internal queue
     * (for potential retrieval via `getNextError()`) AFTER the callback is invoked.
     * If false, errors are only reported via the callback and not stored for `getNextError()`.
     * This allows the caller to decide the queuing strategy when they set their callback.
     */
    void setErrorCallback(std::function<void(const errors::ErrorHandler::ErrorInfo&)> callback, bool enqueueErrorsAfterCallback = true) {
        m_errorHandlerInstance.setErrorCallback(std::move(callback), enqueueErrorsAfterCallback);
    }

    /**
     * @brief Sets an error via the internal `errors::ErrorHandler`.
     * This will trigger any registered callback and, if configured (either at creation or via `setErrorCallback`),
     * enqueue the error. This method is typically used by the LIBRARY code to report errors.
     * @see errors::ErrorHandler::setError
     * @param[in] msg The descriptive error message.
     * @param[in] code The `common_defs::ErrorCode` associated with this error.
     * @param[in] severity The severity of the error.
     * @param[in] source The source of the error.
     */
    void setError(const std::string& msg, errors::ErrorCode code, errors::ErrorSeverity severity = errors::ErrorSeverity::Error, const std::string& source = "") {
        m_errorHandlerInstance.setError(msg, code, severity, source);
    }

    /**
     * @brief Retrieves and removes the next error from the internal `errors::ErrorHandler`'s queue.
     * This is useful if errors are enqueued and the CALLER wishes to poll for them.
     * @see errors::ErrorHandler::getNextError
     * @return An `std::optional<errors::ErrorHandler::ErrorInfo>` containing the error if one exists,
     * otherwise `std::nullopt`.
     */
    [[nodiscard("Return value indicates if an error was present and should be checked.")]]
    std::optional<errors::ErrorHandler::ErrorInfo> getNextError() {
        return m_errorHandlerInstance.getNextError();
    }

    /**
     * @brief Checks if there are any errors in the internal `errors::ErrorHandler`'s queue.
     * @see errors::ErrorHandler::hasError
     * @return True if there is at least one error in the queue, false otherwise.
     */
    [[nodiscard("Return value indicates presence of errors and should be checked.")]]
    bool hasError() const noexcept {
        return m_errorHandlerInstance.hasError();
    }

    /**
     * @brief Gets the error message of the first error in the internal queue without removing it.
     * @see errors::ErrorHandler::getErrorMessage
     * @param[in] removeError Flag indicating whether to remove the error from the queue.
     * @return The error message string. Returns an empty string if the queue is empty.
     */
    [[nodiscard("Return value provides error information and should be checked.")]]
    std::string getErrorMessage(bool removeError = false)  noexcept {
        return m_errorHandlerInstance.getErrorMessage(removeError);
    }

    /**
     * @brief Gets the error code of the first error in the internal queue without removing it.
     * @see errors::ErrorHandler::getErrorCode
     * @param[in] removeError Flag indicating whether to remove the error from the queue.
     * @return The `common_defs::ErrorCode`. Returns `common_defs::ErrorCode::Success` if the queue is empty.
     */
    [[nodiscard("Return value provides error information and should be checked.")]]
    errors::ErrorCode getErrorCode(bool removeError = false)  noexcept {
        return m_errorHandlerInstance.getErrorCode(removeError);
    }

    /**
     * @brief Gets the total number of errors currently in the internal `errors::ErrorHandler`'s queue.
     * @see errors::ErrorHandler::getErrorCount
     * @param[in] level The severity level of the error.
     * @return The count of errors in the queue.
     */
    [[nodiscard("Return value provides error count and should be checked.")]]
    size_t getErrorCount(int level = -1) noexcept {
        return m_errorHandlerInstance.getErrorCount(level);
    }

    /**
     * @brief Clears all errors from the internal `errors::ErrorHandler`'s queue.
     * @see errors::ErrorHandler::clearErrors
     */
    void clearErrors() noexcept {
        m_errorHandlerInstance.clearErrors();
    }
};

} // namespace utils
